﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EzDesk.Apps.Model.Attendance;
using EzDesk.EzAppApi.Utility;
using EzDesk.Utility.Extensions;
using EzDesk.Utility.Json;
using EzDesk.Utility.Log;
using EzDesk.Apps.ServiceImpl.Attendance.Repositories.Interface;
using EzDesk.Utility.ServiceStatusInfo;

namespace EzDesk.Apps.ServiceImpl.Attendance
{
    public partial class AttendanceService
    {
        #region [ private methods]

        /// <summary>
        /// 转换完整的EvaluationModifyApplication实体
        /// </summary>
        /// <param name="applicaiton"></param>
        private EvaluationModifyApplicaiton convertEvaluationModifyApplicationModel(EvaluationModifyApplicaiton applicaiton)
        {
            if (applicaiton != null)
            {
                if (applicaiton.ApplyUserId != Guid.Empty)
                {
                    applicaiton.ApplyUser = _ezApiClient.GetSimpleUserById(applicaiton.ApplyUserId);
                }
            }
            return applicaiton;
        }

        /// <summary>
        /// 转换完整的convertEvaluationHistoryList实体
        /// </summary>
        /// <param name="evaluationModifyHistory"></param>
        private IList<EvaluationModifyHistory> convertEvaluationHistoryListModel(IList<EvaluationModifyHistory> evaluationModifyHistory)
        {
            if (evaluationModifyHistory != null)
            {
                foreach (EvaluationModifyHistory modifyHistory in evaluationModifyHistory)
                {
                    if (modifyHistory.OperatorId != Guid.Empty)
                    {
                        modifyHistory.Operator = _ezApiClient.GetSimpleUserById(modifyHistory.OperatorId);
                    }
                }
            }

            return evaluationModifyHistory;
        }

        /// <summary>
        /// 获得某一天能够得到的额外工时
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        private int getExtraManhours(Guid userId, DateTime date)
        {

            return 0;
            // todo: 前一天晚上10点以后下班，则获得1小时额外工时
            throw new NotImplementedException();
        }

        /// <summary>
        /// 重新评估考勤情况并获得评估结果
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        private DayAttendanceEvaluation evaluateAttendanceInfo(Guid userId, DateTime date)
        {
            var config = getAttendanceConfig();
            var attendanceInfoList = GetAttendanceInfoListByUserInDay(date, userId).Result;
            var dayInfo = GetDayInfo(userId, date).Result;
            var dayLeaveInfo = GetDayLeaveInfo(userId, date).Result;
            int extraManhours = getExtraManhours(userId, date);

            var evaluator = new AttendanceEvaluator(
                userId,
                config,
                attendanceInfoList,
                dayInfo,
                dayLeaveInfo,
                extraManhours
                );
            return evaluator.GetAttendanceEvaluation();
        }

        /// <summary>
        /// 尝试寻找修改过的考勤评估情况
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        private DayAttendanceEvaluation getModifiedAttendanceEvaluation(Guid userId, DateTime date)
        {
            return _modifiedEvaluationRepository.GetByUserAndDate(userId, date);
        }

        /// <summary>
        /// 更新自定义考勤评估状况
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="newAttendanceEvaluation"></param>
        private void addNewEvaluationModify(DayAttendanceEvaluation newAttendanceEvaluation, Guid userId, DateTime dateTime)
        {
            var evaluation = _modifiedEvaluationRepository.GetByUserAndDate(userId, dateTime);
            if (evaluation != null)
            {
                _modifiedEvaluationRepository.Delete(evaluation.Id, true);
            }
            _modifiedEvaluationRepository.Add(newAttendanceEvaluation, true);

        }

        /// <summary>
        /// 添加一个新的修改考勤情况评估申请
        /// </summary>
        /// <param name="modifyApplicaiton"></param>
        private void addNewModifyAttendanceEvaluationApplication(EvaluationModifyApplicaiton modifyApplicaiton)
        {
            _evaluationApplicationRepository.Add(modifyApplicaiton, true);
        }

        /// <summary>
        /// 更新考勤评估状况修改申请状态
        /// </summary>
        /// <param name="attendanceEvaluationApplication"></param>
        private void updateAttendanceEvaluationModifyApplication(EvaluationModifyApplicaiton attendanceEvaluationApplication)
        {
            _evaluationApplicationRepository.Update(attendanceEvaluationApplication, true);
        }


        /// <summary>
        /// 直接获得当前正在惊醒中的考勤状况修改评估申请
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        private EvaluationModifyApplicaiton getCurrentAttendanceEvaluationModifyApplication(Guid userId, DateTime date)
        {
            var applicationList = _evaluationApplicationRepository.GetModifyEvaluationApplicationByUserAndDate(userId, date);
            EvaluationModifyApplicaiton latestApplication = null;

            // 按时间顺序找最新的一个
            if (applicationList != null)
            {
                latestApplication = applicationList
                    .Where(p => p.State == ApplyState.Applying)
                    .OrderByDescending(p => p.ApplyOn)
                    .FirstOrDefault();
            }
            latestApplication = convertEvaluationModifyApplicationModel(latestApplication);
            return latestApplication;
        }

        /// <summary>
        /// 获得某人所有的考勤评估申请
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        private IList<EvaluationModifyApplicaiton> getModifyAttendanceEvaluationApplicaitons(Guid userId, DateTime date)
        {
            var applications = _evaluationApplicationRepository.GetModifyEvaluationApplicationByUserAndDate(userId, date);
            foreach (var applicaiton in applications)
            {
                applicaiton.ApplyUser = _ezApiClient.GetSimpleUserById(applicaiton.ApplyUserId);
            }
            return applications;
        }

        /// <summary>
        /// 将考勤评估变化添加到修改历史
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="oldAttendanceEvalution"></param>
        /// <param name="newAttendanceEvaluation"></param>
        /// <param name="operatorId"></param>
        private void addAttendanceEvaluationModifyToHistroy(
            DayAttendanceEvaluation oldAttendanceEvalution,
            DayAttendanceEvaluation newAttendanceEvaluation,
            Guid operatorId)
        {
            _evaluationModifyHistoryRepository.AddModifyHistory(
                oldAttendanceEvalution,
                newAttendanceEvaluation,
                operatorId,
                DateTime.Now
                );
        }

        /// <summary>
        /// 为考勤添加一个考勤申请拒绝历史
        /// </summary>
        /// <param name="theApplication"></param>
        /// <param name="actorId"></param>
        private void addAttendanceEvaluationRejectionToHistroy(EvaluationModifyApplicaiton theApplication, Guid actorId)
        {
            _evaluationModifyHistoryRepository.Add(new EvaluationModifyHistory()
                                                       {
                                                           Id = Guid.NewGuid(),
                                                           UserId = theApplication.ApplyUserId,
                                                           Date = theApplication.Date,
                                                           OperatorId = actorId,
                                                           ModifyOn = DateTime.Now
                                                       }, true);
        }

        /// <summary>
        /// 取得考勤评估修改的历史
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        private IList<EvaluationModifyHistory> getAttenanceEvaluationModifyHistory(Guid userId, DateTime date)
        {
            return convertEvaluationHistoryListModel(
                _evaluationModifyHistoryRepository.GetModifyHistoryByUserAndDate(userId, date)
                );
        }



        /// <summary>
        /// 申请修改考勤评估后，发送Feed
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="date"></param>
        /// <param name="applyText"></param>
        private void sendApplyEvaluationModifyFeed(Guid userId, DateTime date, string applyText)
        {
            var senderUser = _ezApiClient.GetSimpleUserById(userId);

            string dateStr = date.ToFullDate();
            string dateEpoch = date.ToEpoch().ToString();

            var feedData = new Dictionary<string, string>
                               {
                                   {"sender", senderUser.Name},
                                   {"dateStr", dateStr},
                                   {"dateEpoch", dateEpoch},
                                   {"targetUserId", userId.ToString()},
                                   {"applyText", applyText},
                               };

            // 发送目标为所有hr
            var memberString = _ezApiClient.GetGroupByName("attendance_hr").MemberString;

            Guid feedId = _ezApiClient.SendFeed(
                FeedTemplateStr_attendance_applyEvaluationModify,
                JsonHelper.ConvertToJson(feedData),
                memberString
                );

            _evaluationApplicationRepository.SetFeedIdToEvaluationApplication(userId, date, feedId);
        }

        /// <summary>
        /// 发送考勤评估信息已经修改的Feed
        /// </summary>
        /// <param name="operatorId"></param>
        /// <param name="newAttendanceEvaluation"></param>
        private void sendEvalationModifiedFeed(Guid operatorId, DayAttendanceEvaluation oldAttendanceEvaluation, DayAttendanceEvaluation newAttendanceEvaluation)
        {
            var operatorUser = _ezApiClient.GetSimpleUserById(operatorId);
            DateTime today = newAttendanceEvaluation.Date;
            string dateStr = today.ToFullDate();
            string dateEpoch = today.ToEpoch().ToString();

           
            var modifyHistroyBuild = new StringBuilder();
            if (newAttendanceEvaluation.IsAbsense != oldAttendanceEvaluation.IsAbsense)
            {
                var isAbsenseOld = "是";
                var isAbsenseNew = "是";
                if (oldAttendanceEvaluation.IsAbsense == false)
                {
                    isAbsenseOld = "否";
                }

                if (newAttendanceEvaluation.IsAbsense == false)
                {
                    isAbsenseNew = "否";
                }
                modifyHistroyBuild.AppendFormat("将旷工 {0} 改为 {1}", isAbsenseOld, isAbsenseNew);
            }
            if (newAttendanceEvaluation.IsExtraWork != oldAttendanceEvaluation.IsExtraWork)
            {
                var isExtraWorkNew = "是";
                var isExtraWorkOld = "是";
                if (oldAttendanceEvaluation.IsExtraWork == false)
                {
                    isExtraWorkOld = "否";
                }
                if (newAttendanceEvaluation.IsExtraWork == false)
                {
                    isExtraWorkNew = "否";
                }
                modifyHistroyBuild.AppendFormat("<ez:br />将加班 {0}改为 {1}", isExtraWorkOld, isExtraWorkNew);
            }
            if (newAttendanceEvaluation.LateMiniutes != oldAttendanceEvaluation.LateMiniutes)
            {
                modifyHistroyBuild.AppendFormat("<ez:br />将迟到 {0} 分钟 改为 {1} 分钟", oldAttendanceEvaluation.LateMiniutes, newAttendanceEvaluation.LateMiniutes);
            }
            if (newAttendanceEvaluation.EarlyMiniutes != oldAttendanceEvaluation.EarlyMiniutes)
            {
                modifyHistroyBuild.AppendFormat("<ez:br />将早退 {0} 分钟 改为 {1} 分钟", oldAttendanceEvaluation.EarlyMiniutes, newAttendanceEvaluation.EarlyMiniutes);
            }
            if (newAttendanceEvaluation.Manhours != oldAttendanceEvaluation.Manhours)
            {
                modifyHistroyBuild.AppendFormat("<ez:br />将获得工时 {0} 小时 改为 {1} 小时", oldAttendanceEvaluation.Manhours.DivEx(10), newAttendanceEvaluation.Manhours.DivEx(10));
            }

            var feedData = new Dictionary<string, string>
                               {
                                   {"actor", operatorUser.Name},
                                   {"dateStr", dateStr},
                                   {"dateEpoch", dateEpoch},
                                   {"modifyHistory", modifyHistroyBuild.ToString()}
                               };

            // 发送给被修改考勤评估的人
            string memberString = newAttendanceEvaluation.UserId.ToString();

            _ezApiClient.SendFeed(
                FeedTemplateStr_attendance_evaluationModified,
                JsonHelper.ConvertToJson(feedData),
                memberString
                );
            
        }


        /// <summary>
        /// 发送申请被拒绝的Feed
        /// </summary>
        private void sendEvalationRejectedFeed(Guid actorId, EvaluationModifyApplicaiton theApplication)
        {
            var actor = _ezApiClient.GetSimpleUserById(actorId);
            var feedData = new Dictionary<string, string>
                               {
                                   {"actor", actor.Name},
                                   {"dateStr", theApplication.Date.ToFullDate()},
                                   {"timeEpoch", theApplication.Date.ToEpoch().ToString()},
                               };
            _ezApiClient.SendFeed(
                FeedTemplateStr_attendance_evaluationRejected,
                JsonHelper.ConvertToJson(feedData),
                theApplication.ApplyUserId.ToString()
                );
        }

        /// <summary>
        /// 根据申请人，申请时间，获得申请修改考勤评估的Feed
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="date"></param>
        private void removeEvalationModifiedFeed(Guid feedId)
        {
            if (feedId != Guid.Empty)
            {
                // 获取，让所有HR的收到的提醒都失效
                var memberString = _ezApiClient.GetGroupByName("attendance_hr").MemberString;
                _ezApiClient.SetFeedIsAvailable(feedId, memberString, false);
            }
        }



        #endregion

        public StatusInfo<DayAttendanceEvaluation> GetDayAttendanceEvaluation(Guid userId, DateTime date)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        LogEx.TRACE("AttendanceService", "开始GetDayAttendanceEvaluation" + userId);
                        date = date.Date;
                        // 尝试寻找修改过的考勤记录
                        DayAttendanceEvaluation dayAttendanceEvaluation = getModifiedAttendanceEvaluation(userId, date);

                        //如果没找到那么重新评估一次考勤记录
                        if (dayAttendanceEvaluation == null)
                        {
                            dayAttendanceEvaluation = evaluateAttendanceInfo(userId, date);
                        }
                        LogEx.TRACE("AttendanceService", "结束GetDayAttendanceEvaluation" + userId);

                        return dayAttendanceEvaluation;
                    });
        }

        public StatusInfo ApplyEvaluationModify(Guid userId, DateTime date, string applyText)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        date = date.Date;

                        if (DateTime.Now.Date <= date)
                        {
                            LogEx.EXCEPT("Attendance - ApplyEvaluationModify", "还没到这一天，没法处理这一天的考勤评估修改");
                        }

                        // 如果已经有提交的正在处理中的申请，那么不允许多次提交
                        if (getCurrentAttendanceEvaluationModifyApplication(userId, date) != null)
                        {
                            LogEx.EXCEPT("Attendance - ApplyEvaluationModify", "重复提交修改考勤评估申请");
                        }

                        var modifyApplicaiton = new EvaluationModifyApplicaiton()
                                                    {
                                                        Id = Guid.NewGuid(),
                                                        ApplyOn = DateTime.Now,
                                                        ApplyUserId = userId,
                                                        ApplyText = applyText,
                                                        Date = date.Date,
                                                        State = ApplyState.Applying,
                                                    };

                        addNewModifyAttendanceEvaluationApplication(modifyApplicaiton);

                        sendApplyEvaluationModifyFeed(userId, date, applyText);
                    });
        }

        public StatusInfo<EvaluationModifyApplicaiton> GetCurrentEvaluationModifyApplication(Guid userId, DateTime date)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        date = date.Date;
                        var application = getCurrentAttendanceEvaluationModifyApplication(userId, date);
                        return application;
                    });
        }

        public StatusInfo<IList<EvaluationModifyApplicaiton>> GetEvaluationModifyApplicaitons(Guid userId, DateTime date)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        date = date.Date;
                        return getModifyAttendanceEvaluationApplicaitons(userId, date);
                    });
        }

        public StatusInfo<IList<EvaluationModifyHistory>> GetEvaluationModifyHistory(Guid userId, DateTime date)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        date = date.Date;
                        return getAttenanceEvaluationModifyHistory(userId, date);
                    });
        }

        public StatusInfo ModifyEvaluation(DayAttendanceEvaluation newAttendanceEvaluation, Guid operatorId)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        var userId = newAttendanceEvaluation.UserId;
                        var date = newAttendanceEvaluation.Date = newAttendanceEvaluation.Date.Date;

                        // 为考勤添加一个考勤历史
                        var oldAttendanceEvaluation = GetDayAttendanceEvaluation(userId, date).Result;
                        addAttendanceEvaluationModifyToHistroy(
                            oldAttendanceEvaluation,
                            newAttendanceEvaluation,
                            operatorId
                            );
                        // 添加一个自定义的考勤评估
                        addNewEvaluationModify(newAttendanceEvaluation, userId, date);

                        // 将当前的考勤申请变为已处理
                        var currentEvaluationApplication = getCurrentAttendanceEvaluationModifyApplication(userId, date);
                        if (currentEvaluationApplication != null)
                        {
                            currentEvaluationApplication.State = ApplyState.Done;
                            updateAttendanceEvaluationModifyApplication(currentEvaluationApplication);

                            // 删除申请修改考勤评估记录的Feed
                            removeEvalationModifiedFeed(currentEvaluationApplication.FeedId);
                        }
                        // 发送考勤评估记录已修改的Feed
                        sendEvalationModifiedFeed(operatorId, oldAttendanceEvaluation, newAttendanceEvaluation);
                    });
        }

        public StatusInfo RejectEvaluationApplication(Guid actorId, Guid applicationId)
        {
            return StatusInfo.Wrap(
                () =>
                    {
                        var theApplication = _evaluationApplicationRepository.GetById(applicationId);

                        // 为考勤添加一个考勤申请拒绝历史
                        addAttendanceEvaluationRejectionToHistroy(theApplication, actorId);

                        if (theApplication.State == ApplyState.Applying)
                        {
                            // 确保这个申请当前有效
                            theApplication.State = ApplyState.Done;
                            updateAttendanceEvaluationModifyApplication(theApplication);

                            removeEvalationModifiedFeed(theApplication.FeedId);
                        }
                        // 发送申请被拒绝的Feed


                        // todo:发送申请被拒绝的Feed
                        sendEvalationRejectedFeed(actorId, theApplication);
                    });
        }

    }
}
